package br.biofoco.p2p.dht;

import static org.slf4j.LoggerFactory.getLogger;

import java.io.IOException;
import java.util.Collection;
import java.util.Iterator;
import java.util.Random;
import java.util.concurrent.Executors;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.TimeUnit;

import org.slf4j.Logger;

import br.biofoco.p2p.peer.PeerNode;
import br.biofoco.p2p.peer.PeerSerializer;
import br.biofoco.p2p.rpc.messaging.MessageException;

public class RandomWalkDHT extends AbstractDHT {

	private static final Logger LOGGER = getLogger(RandomWalkDHT.class);
	
	private final ScheduledExecutorService executor = Executors.newScheduledThreadPool(5);

	public RandomWalkDHT(PeerNode peerNode, PeerSerializer peerSerializer, SeedProvider seedProvider) {
		super(peerNode, peerSerializer, seedProvider);	
	}


	public void start() throws IOException {
		LOGGER.info("Starting DHT service...");		
		startPeriodicServices();
	}



	public void stop() throws IOException {
		LOGGER.info("stopping DHT service...");
		executor.shutdown();
		peerView.clear();
	}

	private void startPeriodicServices() {
//		executor.scheduleAtFixedRate(new KeepAlive(), 60000, 60000, TimeUnit.MILLISECONDS);
		LOGGER.info("Starting executor...");	
		executor.scheduleAtFixedRate(new ExchangeView(), 10, 10, TimeUnit.SECONDS);
		LOGGER.info("Finishing executor...");	
	}
	

	public void put(long id, byte[] data) {

		if (peerView.keySet().size() > 0) {

			long pos = id % peerView.keySet().size();

			long count = 0;
			for (PeerNode node : peerView.values()) {
				if (pos == count) {
					LOGGER.debug("Armazenando no peer " + node);
					break;
				}
				count++;
			}
		}
	}

	public byte[] get(long id) {

		if (peerView.keySet().size() > 0) {
			long pos = id % peerView.keySet().size();

			long count = 0;
			for (PeerNode node : peerView.values()) {
				if (pos == count) {
					LOGGER.debug("Armazenando no peer " + node);
					break;
				}
				count++;
			}
		}
		return null;
	}

	private class ExchangeView implements Runnable {

		private Random rand = new Random(System.nanoTime());

		@Override
		public void run() {
			LOGGER.debug("PEER-VIEW:");
			if (!peerView.isEmpty()) {

				PeerNode[] peers = peerView.values().toArray(new PeerNode[0]);
				PeerNode p = peers[rand.nextInt(peers.length)];

				boolean error = false;
				try {
					LOGGER.debug("RandomWalkDHT.run() - Starting EXCHANGE peer view. "); 
					Collection<PeerNode> itsView = exchangePeerView(p, peerView.values());	
					LOGGER.debug("RandomWalkDHT.run() - FINISHED EXCHANGE peer view. "); 
					for (PeerNode pn : itsView) {
						LOGGER.debug("RandomWalkDHT.run() - Peer de ID " + pn.getPeerID() + " inserido na tabela view.");
						peerView.put(pn.getPeerID(), pn);
					}
					
					Iterator<PeerNode> it = peerView.values().iterator();
					LOGGER.debug("**************** VIEWS *************");
					LOGGER.debug("PEER-VIEW:");
					while(it.hasNext()){
						LOGGER.debug("PEER: " + it.next().toString());
					}
					LOGGER.debug("*******************************************");
					//LOGGER.debug("PEER-VIEW: " + peerView.values());
					

				} catch (MessageException e) {
					LOGGER.error("RandomWalkDHT.run() - Message exception error = " + e.getMessage());
					e.printStackTrace();
					error = true;
					
				} catch (IOException e) {
					LOGGER.error("RandomWalkDHT.run() - I/O error = " + e.getMessage());	
					e.printStackTrace();
					error = true;
				}
				
//				if (error) {
//					peerView.remove(p.getPeerID());									
//					LOGGER.error("PEER VIEW: " + peerView.keySet());
//				}
			}
		}
	}		

//	public class KeepAlive implements Runnable {
//
//		private int next = 0;
//
//		@Override
//		public void run() {
//			
//			System.out.println("running keep alive");
//
//			if (!peerView.isEmpty()) {
//
//				PeerNode[] peers = peerView.values().toArray(new PeerNode[0]);
//				PeerNode p = peers[next];
//
//				try {
//
//					ping(p);
////					twoWayPing(p);
//
//					next++;
//
//				} catch (MessageException e) {
//					System.out.println(e.getMessage() + " removing peer from view ");
//					peerView.remove(p.getPeerID());
//					evictionList.add(p);
//					System.out.println("PEER VIEW: " + peerView);
//				}
//				next = next % peerView.size();
//			}
//		}
//	}


}
